﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Timers;
using System.Threading;
using System.Windows.Media.Animation;
using System.Globalization;
namespace JapaneseMusicHtmlCreator
{
    /// <summary>
    /// PageKashiEdit.xaml 的交互逻辑
    /// </summary>
    public partial class PageKashiEdit : Page
    {
        private MainWindow mainWindow;
        private Path pathPlay = null;
        private Path pathPause = null;
        private Canvas canvas = null;
        public bool bPlayState = false;
        private  System.Timers.Timer musicTimer=null;
        private bool bSlideState = false;
        private string lastLyric = "";
        public PageKashiEdit(MainWindow mainWindow)
        {
            
            InitializeComponent();
            this.mainWindow = mainWindow;
            pathPlay = new Path();
            PathFigure figure = new PathFigure();
            figure.StartPoint = new Point(9.43548, 6.51382);
            figure.Segments.Add(new LineSegment(new Point(21.99309, 14.80876), true));
            figure.Segments.Add(new LineSegment(new Point(9.55069, 23.79493), true));
            figure.IsClosed = true;
            PathGeometry pg = new PathGeometry();
            pg.Figures.Add(figure);
            pathPlay.Fill = Brushes.Green;
            pathPlay.Stroke = Brushes.Black;
            pathPlay.StrokeThickness = 1;
            pathPlay.StrokeStartLineCap = PenLineCap.Round;
            pathPlay.Data = pg;
            pathPause = new Path();
            pg=new PathGeometry();
            pg.AddGeometry(new RectangleGeometry(new Rect(8, 7, 3.45622, 16.47466)));
            pg.AddGeometry(new RectangleGeometry(new Rect(16, 7, 3.45622, 16.47466)));
            pathPause.Fill = Brushes.Red;
            pathPause.Stroke = Brushes.Black;
            pathPause.StrokeThickness = 1;
            pathPause.StrokeStartLineCap = PenLineCap.Round;
            pathPause.Data = pg;
            musicTimer = new System.Timers.Timer(20);
            musicTimer.Elapsed += musicTimer_Elapsed;
            slTime.AddHandler(Slider.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(slTime_PreviewMouseLeftButtonDown), true);
            slTime.AddHandler(Slider.PreviewMouseLeftButtonUpEvent, new MouseButtonEventHandler(slTime_PreviewMouseLeftButtonUp), true);
            slTime.AddHandler(Slider.PreviewMouseMoveEvent, new MouseEventHandler(slTime_PreviewMouseMove), true);  
        }
           
    
        private void slTime_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            bSlideState = true;
        }
        private void slTime_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (bSlideState)
            {
                Duration total = mainWindow.mediaPlayer.NaturalDuration;
                tbTimeHint.Text = TimeHintText(TimeSpan.FromMilliseconds(slTime.Value * total.TimeSpan.TotalMilliseconds / 100));
            }
        }
        private void slTime_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (bSlideState)
            {
                Duration total = mainWindow.mediaPlayer.NaturalDuration;
                mainWindow.mediaPlayer.Position = TimeSpan.FromMilliseconds(slTime.Value * total.TimeSpan.TotalMilliseconds / 100);
            }
            bSlideState = false;
        }
        private string TimeHintText(Duration d)
        {
            int milli = d.TimeSpan.Milliseconds/10;
            int second = d.TimeSpan.Seconds;
            int minute = d.TimeSpan.Minutes;
            return string.Format("{0:D2}:{1:D2}.{2:D2}", minute, second, milli);
        }
        void musicTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                Action action = () =>
                {
                    
                    if (!bSlideState)
                    {

                        try
                        {
                            
                            Duration d = mainWindow.mediaPlayer.Position;
                            Duration total = mainWindow.mediaPlayer.NaturalDuration;
                            tbTimeHint.Text = TimeHintText(d);
                            slTime.Value = d.TimeSpan.TotalMilliseconds * 100 / total.TimeSpan.TotalMilliseconds;
                            int currentline = GetCurrentLineByLyrics();
                            if (currentline != -1)
                            {
                                KashiShow s = ChangeKashiToNormal(GetKashis(), currentline);
                                if (!lastLyric.Equals(s.Kashi))
                                {
                                    SetKashiShow(s);
                                    lastLyric = s.Kashi;
                                }
                            }
                            else
                            {
                                KashiShow s = new KashiShow();
                                if (!lastLyric.Equals(s.Kashi))
                                {
                                    SetKashiShow(s);
                                    lastLyric = s.Kashi;
                                }
                            }
                        }
                        catch (InvalidOperationException ex)
                        {

                        }
                    }
                };
                this.Dispatcher.Invoke(action);
            }
            catch (TaskCanceledException ex)
            {

            }
           
        }

        private void SetKashiShow(KashiShow p)
        {

            tbTempLyric2.Inlines.Clear();
            Inline[] i=new Inline[tbTempLyric.Inlines.Count];
            tbTempLyric.Inlines.CopyTo(i, 0);
            for (int j = 0; j < tbTempLyric.Inlines.Count; j++)
            {
                Inline k=null;
                if (i[j] is Run)
                {
                    k = new Run();
                    Run l = (Run)k;
                    l.Text = (i[j] as Run).Text;
                    l.Foreground = (i[j] as Run).Foreground;
                    l.FontSize = (i[j] as Run).FontSize ;
                }
                else if(i[j] is LineBreak)
                {
                    k = new LineBreak();
                }
                tbTempLyric2.Inlines.Add(k);
            }
            tbTempLyric2.Padding = tbTempLyric.Padding;
            ConvertKashi(tbTempLyric,p.Kashi);
            if (p.Translate != "")
            {
                tbTempLyric.Inlines.Add(new LineBreak());
                tbTempLyric.Inlines.Add(new Run(p.Translate) {Foreground=Brushes.DarkGreen });
                tbTempLyric.Padding = new Thickness(0);
            }
            else
            {
                tbTempLyric.Padding = new Thickness(0, 10, 0, 0);
            }
            DoubleAnimation d1 = new DoubleAnimation(60, 0, TimeSpan.FromSeconds(0.4));
            DoubleAnimation d2 = new DoubleAnimation(0, -60, TimeSpan.FromSeconds(0.4));
            tbTempLyric.BeginAnimation(Canvas.TopProperty, d1);
            tbTempLyric2.BeginAnimation(Canvas.TopProperty, d2);
        }



        private void ConvertKashi(TextBlock t,string p)
        {
            InlineCollection ic = t.Inlines;
            ic.Clear();
          
            int kanji=0;
            int lastkanji=0;
            for (int i = 0; i < p.Length; i++)
            {
         
                if (p[i] == '$' && kanji==0)
                {
                    kanji = 1;
                }
               
                else if (p[i]=='$'&&kanji==1)
                {
                    kanji = 2;
                  
                }
                else if (p[i] =='#'&&kanji==2)
                {
                    kanji=0;
                }
                if (lastkanji != kanji)
                {
                    if (kanji == 2)
                    {
                        ic.Add(new Run("(") { Foreground=Brushes.Red});
                    }
                    if (kanji == 0)
                    {
                        ic.Add(new Run(")") { Foreground = Brushes.Red });
                    }
                }
                Run run;
                if(p[i]!='#'&&p[i]!='$')
                switch (kanji)
                {

                    case 0:
                        run = new Run();
                        run.Text = new string(p[i], 1);
                        ic.Add(run);
                        break;
                    case 1:
                        run = new Run();
                        run.Foreground = Brushes.Blue;
                        run.FontSize = 13;
                        run.Text = new string(p[i], 1);
                        ic.Add(run);
                        break;
                    case 2:
                        run = new Run();
                        run.Foreground = Brushes.Red;
                        run.Text = new string(p[i], 1);
                        ic.Add(run);
                        break;
                    default:
                        break;
                }
                lastkanji = kanji;
                  
            }
           
        }

        private KashiShow ChangeKashiToNormal(string[] p, int currentline)
        {
            KashiShow ret = new KashiShow();
            string[] s=p[currentline].Split(']');
            if (s.Length > 1)
            {
                string[] s2 = s[1].Split('@');
                if (s2.Length > 1)
                {
                    ret.Kashi = s2[0];
                    ret.Translate = s2[1];
                }
                else
                {
                    ret.Kashi = s[1];
                }
            }
               

            return ret;
        }

        private int GetCurrentLineByLyrics()
        {
   
            try
            {
                string[] kashis = GetKashis();
                List<int> list = new List<int>();
                for (int i = 0; i < kashis.Length; i++)
                {
                    string[] temp = kashis[i].Split(']');
                    if (temp.Length > 1)
                    {
                        int minute = int.Parse(temp[0].Substring(1, 2));
                        int second = int.Parse(temp[0].Substring(4, 2));
                        int milli = int.Parse(temp[0].Substring(7, 2));
                        int totalmilli = minute * 60000 + second * 1000 + milli*10;
                        int totalm = (int)mainWindow.mediaPlayer.Position.TotalMilliseconds;
                        if (totalmilli < totalm)
                            list.Add(totalmilli);
                    }

                }
                return list.Count - 1;
            }
            catch
            {
                return -1;
            }
                
        }

        private void btnNext_Click(object sender, RoutedEventArgs e)
        {
            SaveMemory();          
            mainWindow.NavigateForward(this, mainWindow.pageSettings);
        }

        private void btnPrev_Click(object sender, RoutedEventArgs e)
        {
            SaveMemory();          
            mainWindow.NavigateBackward(this, mainWindow.pageInformation);
        }

        private void SaveMemory()
        {
            mainWindow.musicKashi = tbKashi.Text;
            bPlayState = false;
            mainWindow.mediaPlayer.Stop();
            mainWindow.mediaPlayer.Close();
            musicTimer.Stop();
            slTime.Value = 0;
            tbTimeHint.Text = "00:00.00";
            if (mainWindow.musicBkgndPath != null)
            {
                mainWindow.pageSettings.bitmapOri = new WriteableBitmap(new BitmapImage(new Uri(mainWindow.musicBkgndPath, UriKind.Absolute)));
                mainWindow.pageSettings.bitmap = new WriteableBitmap(new BitmapImage(new Uri(mainWindow.musicBkgndPath, UriKind.Absolute)));                
            }
            if (mainWindow.musicBkgndPath2 != null)
            {
                mainWindow.pageSettings.bitmapOri2 = new WriteableBitmap(new BitmapImage(new Uri(mainWindow.musicBkgndPath2, UriKind.Absolute)));
                mainWindow.pageSettings.bitmap2 = new WriteableBitmap(new BitmapImage(new Uri(mainWindow.musicBkgndPath2, UriKind.Absolute)));             
            }
            mainWindow.pageSettings.FreshImg();
            
        }
        public void SetPlayButtonState(bool b)
        {
            
            if (canvas != null)
            {
                canvas.Children.Clear();

                if (b)//Play
                {
                    canvas.Children.Add(pathPlay);
                }
                else
                {
                    canvas.Children.Add(pathPause);
                }
            }
        }

        private void btnPlayStop_Click(object sender, RoutedEventArgs e)
        {
            Q();
        }
        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
            canvas= btnPlayStop.Template.FindName("canvas",btnPlayStop) as Canvas;
            SetPlayButtonState(true);
        
        }

   

        private void btnForward1s_Click(object sender, RoutedEventArgs e)
        {
            Right();
        }

        private void btnBackward1s_Click(object sender, RoutedEventArgs e)
        {
            Left();
        }

        private void btnNote_Click(object sender, RoutedEventArgs e)
        {
            M();
        }

        private void ModifyKashis(string[] kashis, int currentline, string kashi)
        {
            string temp="";
            kashis[currentline] = kashi;
            int i=0;
            for (; i < kashis.Length - 1; i++)
            {
                temp += kashis[i] + "\n";
            }
            temp += kashis[i];
            tbKashi.Text = temp;
            
        }

        private void btnReset_Click(object sender, RoutedEventArgs e)
        {
            R();
            
        }

        private string[] GetKashis()
        {
            string[] s= tbKashi.Text.Split('\n');
            for (int i = 0; i < s.Length; i++)
            {
                if (s[i].EndsWith("\r"))
                {
                    s[i] = s[i].Substring(0, s[i].Length - 1);
                }
            }
            return s;
        }

        private void SelectFirstLine()
        {
            string[] kashis = GetKashis();
            tbKashi.Focus();
            tbKashi.Select(0,1);
            tbKashi.ScrollToVerticalOffset(0);
            tbKashi.ScrollToHorizontalOffset(0);
        }
        private void SelectLine(string[] kashis,int lineNum)
        {
            int pos = 0;
            tbKashi.Focus();
            for (int i = 0; i < lineNum; i++)
                pos += kashis[i].Length+1;
            if (lineNum < kashis.Length)
            {
                tbKashi.Select(pos, 1);
                tbKashi.ScrollToVerticalOffset(16 * lineNum - 200);
                tbKashi.ScrollToHorizontalOffset(0);
            }
        }
        private void SelectLine2(string[] kashis, int lineNum,int start,int len)
        {
            int pos = 0;
            tbKashi.Focus();
            for (int i = 0; i < lineNum; i++)
                pos += kashis[i].Length + 1;
            tbKashi.Select(pos+start, len);
            tbKashi.ScrollToVerticalOffset(16 * lineNum - 200);
            tbKashi.ScrollToHorizontalOffset(0);
        }
        private int GetLine(string[] kashis, int pos)
        {
            int ret = 0;
            for (int i = 0; i < kashis.Length; i++)
            {
                if (pos >= 0)
                {
                    pos -= (kashis[i].Length+1);
                    ret++;
                }
            }
            return ret-1;
        }
        private int GetPosInLine(string[] kashis,int pos, int line)
        {
            int p = 0;
           
            for (int i = 0; i < line; i++)
            {
                p += kashis[i].Length+1;
            }
            return pos - p;
        }

        private void btnAddTranslate_Click(object sender, RoutedEventArgs e)
        {
            T();
            

        }

        private void btnNetEase_Click(object sender, RoutedEventArgs e)
        {
            string[] kashis = GetKashis();
            if (kashis.Length > 1)
            {
                string[] temp = new string[kashis.Length / 2];
                string str = "";
                int j = 0;
                for (int i = 0; i < kashis.Length / 2; i++)
                {
                    temp[i] = kashis[2*i] + "@" + kashis[2*i + 1];
                }
                for (; j < temp.Length - 1; j++)
                {
                    str += temp[j] + "\n";
                }
                str += temp[j];
                tbKashi.Text = str;
            }
        }

        private void btnAddKana_Click(object sender, RoutedEventArgs e)
        {
            K();
            
        }

        private void btnMinus10m_Click(object sender, RoutedEventArgs e)
        {
            string[] kashis = GetKashis();
            int currentline = GetLine(kashis, tbKashi.SelectionStart);

            string[] temp = kashis[currentline].Split(']');
            if (temp.Length > 1)
            {
                int minute = int.Parse(temp[0].Substring(1, 2));
                int second = int.Parse(temp[0].Substring(4, 2));
                int milli = int.Parse(temp[0].Substring(7, 2));
                int totalmilli = minute * 60000 + second * 1000 + milli*10;
                totalmilli -= 50;
                if (totalmilli < 0) totalmilli = 0;
                TimeSpan span = TimeSpan.FromMilliseconds(totalmilli);
                minute = span.Minutes;
                second = span.Seconds;
                milli = span.Milliseconds/10;
                string t = string.Format("[{0:D2}:{1:D2}.{2:D2}]", minute, second, milli);
                ModifyKashis(kashis, currentline, t + temp[1]);
                SelectLine(kashis, currentline);

            }
        }

        private void btnPlus10m_Click(object sender, RoutedEventArgs e)
        {
            string[] kashis = GetKashis();
            int currentline = GetLine(kashis, tbKashi.SelectionStart);

            string[] temp = kashis[currentline].Split(']');
            if (temp.Length > 1)
            {
                int minute = int.Parse(temp[0].Substring(1, 2));
                int second = int.Parse(temp[0].Substring(4, 2));
                int milli = int.Parse(temp[0].Substring(7, 2));
                int totalmilli = minute * 60000 + second * 1000 + milli*10;
                totalmilli += 50;
                if (totalmilli >600000) totalmilli = 600000;
                TimeSpan span = TimeSpan.FromMilliseconds(totalmilli);
                minute = span.Minutes;
                second = span.Seconds;
                milli = span.Milliseconds / 10;
                string t = string.Format("[{0:D2}:{1:D2}.{2:D2}]", minute, second, milli);
                ModifyKashis(kashis, currentline, t + temp[1]);
                SelectLine(kashis, currentline);

            }
        }

        private void tbKashi_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
            {
                bool b = true;
                switch (e.Key)
                {
                 
                    case Key.K:
                        K();
                        break;
                    case Key.T:
                        T();
                        break;
                    case Key.Q:
                        Q();
                        break;
                    default:
                        b = false;
                        break;
                }
                if (b)
                {
                    e.Handled = true;
                }
            }
            if (bPlayState)
            {
                if (e.Key == Key.Space)
                {
                    M();
                    e.Handled = true;
                  
                }
                 if (e.Key == Key.Left)
                {
                    Left();
                    e.Handled = true;
                 
                }
                 if (e.Key == Key.R)
                {
                    R();
                    e.Handled = true;
                   
                }
                 if (e.Key == Key.Right)
                {
                    Right();
                    e.Handled = true;

                } if (e.Key == Key.Up)
                 {
                     Up();
                     e.Handled = true;

                 }
                 if (e.Key == Key.Down)
                 {
                     Down();
                     e.Handled = true;

                 }
                 
            }
        }

        private void Up()
        {
            string[] kashis = GetKashis();
            int i = GetLine(kashis, tbKashi.SelectionStart);

            SelectLine(kashis, i - 1);


        }

        private void Down()
        {
            string[] kashis = GetKashis();
            int i = GetLine(kashis, tbKashi.SelectionStart);

            SelectLine(kashis, i + 1);


        }

        private void R()
        {
            SelectFirstLine();
            mainWindow.mediaPlayer.Position = TimeSpan.FromMilliseconds(0);
            slTime.Value = 0;
            tbTimeHint.Text = "00:00.00";
        }

        private void T()
        {
            string[] kashis = GetKashis();
            int currentline = GetLine(kashis, tbKashi.SelectionStart);
            string s = kashis[currentline];
            WindowAddTranslate window = new WindowAddTranslate();
            window.Owner = mainWindow;
            window.ori = s;
            window.ShowDialog();
            if (window.tra != null)
            {
                s += "@" + window.tra;
            }
            ModifyKashis(kashis, currentline, s);
            SelectLine(kashis, currentline);
        }

        private void M()
        {
            string[] kashis = GetKashis();
            int pos = tbKashi.SelectionStart;
            int len = tbKashi.SelectionLength;
            int currentline = GetLine(kashis, pos);
            string kashi = kashis[currentline];
            kashi = kashi.Trim();
            string[] temp = kashi.Split(']');
            if (temp.Length > 1)
            {
                kashi = temp[1];
            }
            Duration d = mainWindow.mediaPlayer.Position;
            kashi = '[' + TimeHintText(d) + ']' + kashi;
            ModifyKashis(kashis, currentline, kashi);
            SelectLine(kashis, currentline + 1);
        }

        private void Right()
        {
            Duration d = mainWindow.mediaPlayer.Position;
            Duration total = mainWindow.mediaPlayer.NaturalDuration;
            double totalm = total.TimeSpan.TotalMilliseconds;
            double m = d.TimeSpan.TotalMilliseconds;
            m += 1000;
            if (m > totalm)
                m = totalm;
            d = TimeSpan.FromMilliseconds(m);
            mainWindow.mediaPlayer.Position = d.TimeSpan;
            tbTimeHint.Text = TimeHintText(d);
            slTime.Value = m * 100 / totalm;
        }


        private void Left()
        {
            Duration d = mainWindow.mediaPlayer.Position;
            Duration total = mainWindow.mediaPlayer.NaturalDuration;
            double totalm = total.TimeSpan.TotalMilliseconds;
            double m = d.TimeSpan.TotalMilliseconds;
            m -= 1000;
            if (m < 0)
                m = 0;
            d = TimeSpan.FromMilliseconds(m);
            mainWindow.mediaPlayer.Position = d.TimeSpan;
            tbTimeHint.Text = TimeHintText(d);
            slTime.Value = m * 100 / totalm;
        }

        private void K()
        {
            try
            {
                string[] kashis = GetKashis();
                int currentline = GetLine(kashis, tbKashi.SelectionStart);
                int currentposinline = GetPosInLine(kashis, tbKashi.SelectionStart, currentline);
                string s = kashis[currentline].Substring(currentposinline, tbKashi.SelectionLength);
                if (!string.IsNullOrWhiteSpace(s))
                {
                    WindowAddKana window = new WindowAddKana();
                    window.Owner = mainWindow;
                    window.ori = s;
                    window.ShowDialog();
                    if (window.tra != null)
                    {
                        string s1 = kashis[currentline].Substring(0, currentposinline);
                        string s2 = kashis[currentline].Substring(currentposinline + tbKashi.SelectionLength, kashis[currentline].Length - currentposinline - tbKashi.SelectionLength);
                        s = "$" + s + "$" + window.tra + "#";
                        ModifyKashis(kashis, currentline, s1 + s + s2);
                        SelectLine2(kashis, currentline, s1.Length, s.Length);

                        double width = GetTextDisplayWidth(s1, tbKashi.FontFamily, tbKashi.FontStyle, tbKashi.FontWeight, tbKashi.FontStretch, tbKashi.FontSize);
                        tbKashi.ScrollToHorizontalOffset(width - 100);

                    }
                }
            }
            catch
            {

            }
            
        }
        private void Q()
        {
            if (!bPlayState)
            {
                bPlayState = true;
                tbKashi.IsReadOnly = true;
                SetPlayButtonState(!bPlayState);
                mainWindow.mediaPlayer.Play();
                musicTimer.Start();
                string[] kashis = GetKashis();
                SelectLine(kashis, GetLine(kashis, tbKashi.SelectionStart));

            }
            else
            {
                bPlayState = false;
                tbKashi.IsReadOnly = false;
                SetPlayButtonState(!bPlayState);
                mainWindow.mediaPlayer.Pause();
                musicTimer.Stop();

            }
        }

        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            int l = tbKashi.SelectionStart + tbKashi.SelectionLength;
            string s = Clipboard.GetText();
            string s3 = "";
            for (int i = 0; i < s.Length; i++)
            {
                if (s[i] != '\r')
                {
                    s3 += s[i];
                }
            }
            string s1 = tbKashi.Text.Substring(0, tbKashi.SelectionStart);
            string s2 = tbKashi.Text.Substring(l, tbKashi.Text.Length - l);
            tbKashi.Text = s1 + s3 + s2;
            tbKashi.Select(s1.Length + s3.Length,0);
            




        }
        public static Double GetTextDisplayWidth(string str, FontFamily fontFamily, FontStyle fontStyle, FontWeight fontWeight, FontStretch fontStretch, double FontSize)
        {
            var formattedText = new FormattedText(
                                str,
                                CultureInfo.CurrentUICulture,
                                FlowDirection.LeftToRight,
                                new Typeface(fontFamily, fontStyle, fontWeight, fontStretch),
                                FontSize,
                                Brushes.Black
                                );
            Size size = new Size(formattedText.Width, formattedText.Height);
            return size.Width;
        }

        
    }
    public class KashiShow
    {
        public string Kashi { get; set; }
        public string Translate { get; set; }

        public KashiShow()
        {
            Kashi = "";
            Translate = "";
        }
    }
}
